package com.caipiao.util;

import jodd.util.StringUtil;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;

public class FtpHelper {
    public static boolean DownLoadFtpFile(FtpParam ftp_param,
                                          String remote_file_path,
                                          String local_file_path,
                                          boolean rename_exist_file,
                                          Logger logger) {
        boolean dl_result = false;

        File local_file = null;
        FTPClient ftpClient = null;
        FileOutputStream localFileStream = null;
        InetAddress address = null;

        try {
            if (null == ftp_param) {
                //参数错误
                throw new Exception("FTP配置错误,无法下载" + remote_file_path);
            }

            local_file = new File(local_file_path);
            if (local_file.exists())    //文件已存在
            {
                // 日志文件已存在
                logger.warn("FTP本地文件已存在:" + local_file_path);

                if (rename_exist_file) {
                    String rename_path = local_file_path + "." + IdMaker.Get_Random_Id(16) + ".bak";
                    File rename_file = new File(rename_path);

                    if (local_file.renameTo(rename_file))    //重命名成功
                    {
                        //重命名成功
                        logger.warn("FTP本地文件重命名成功:" + rename_path);
                    } else {
                        //重命名失败
                        throw new Exception("FTP本地文件重命名失败:" + rename_path);
                    }
                } else    //不重命名
                {
                    throw new Exception("FTP本地文件已存在,未重命名:" + local_file_path);
                }
            } else {
                String parent_path = local_file.getParent();
                File parent_dir = new File(parent_path);

                //上级目录不存在,生成
                if (!parent_dir.exists()) {
                    parent_dir.mkdirs();
                }
            }

            address = InetAddress.getByName(ftp_param.ftp_ip);

            ftpClient = new FTPClient();

            ftpClient.setConnectTimeout(10 * 1000);
            ftpClient.setDefaultTimeout(10 * 1000);
            ftpClient.setDataTimeout(60 * 1000);

            ftpClient.connect(address, ftp_param.ftp_port);

            logger.trace("FTP开始连接" + ftp_param.ftp_ip + ":" + ftp_param.ftp_port);

            //登录失败
            if (!ftpClient.login(ftp_param.user_name, ftp_param.password)) {
                //日志,用户名密码错误
                throw new Exception("FTP登录失败:login_name:" + ftp_param.user_name + " login_psw:" + ftp_param.password);
            }

            //设置PASV模式
            if (ftp_param.pasv_mode) {
                ftpClient.enterLocalPassiveMode();

                if (!(ftpClient.pasv() == FTPReply.ENTERING_PASSIVE_MODE)) {
                    //设置FTP PASV模式失败
                    throw new Exception("FTP Pasv模式设置失败");
                }
                logger.trace("FTP Pasv模式设置成功");
            }

            localFileStream = new FileOutputStream(local_file_path);

            ftpClient.setBufferSize(1024);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.retrieveFile(remote_file_path, localFileStream);

            //FTP下载失败
            if ((ftpClient.getReplyCode() != FTPReply.CLOSING_DATA_CONNECTION)) {
                //日志
                throw new Exception("FTP下载失败,FtpReplayCode:" + ftpClient.getReplyCode());
            }

            logger.debug("FTP下载文件成功,保存于:" + local_file_path);

            //到此下载成功
            dl_result = true;
        } catch (Exception e) {
            //日志 下载文件异常
            logger.error("FTP下载异常:" + e);
        } finally {
            try {
                if (localFileStream != null) {
                    localFileStream.flush();
                    localFileStream.close();
                }

                if (null != ftpClient) {
                    ftpClient.disconnect();
                }

                if (!dl_result)    //下载失败
                {
                    local_file = new File(local_file_path);
                    if (local_file.exists()) {
                        local_file.delete();
                        logger.trace("FTP 下载失败,清理临时文件成功");
                    }
                }
            } catch (Exception e) {
                //出现异常
                logger.error("FTP下载失败,finally异常:" + e);
            }
        }
        return dl_result;
    }

    /**
     * @param path 上传到ftp服务器哪个路径下，空时传到ftp用户根目录
     * @param file 上传的文件或文件夹
     * @throws Exception
     */
    public static boolean uploadFile(String path, FtpParam ftp_param, File file,
                                     Logger logger) {
        boolean flag = false;
        //链接ftp
        FTPClient ftp = new FTPClient();
        int reply;

        do {
            try {
                ftp.connect(ftp_param.ftp_ip, ftp_param.ftp_port);
                ftp.login(ftp_param.user_name, ftp_param.password);
                ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            } catch (IOException e) {
                logger.error(ftp_param.msgId, e);
                logger.error(ftp_param.msgId + " - 链接ftp失败");
                break;
            }

            try {
                //设置PASV模式
                if (ftp_param.pasv_mode) {
                    ftp.enterLocalPassiveMode();

                    if (!(ftp.pasv() == FTPReply.ENTERING_PASSIVE_MODE)) {
                        //设置FTP PASV模式失败
                        throw new Exception("FTP Pasv模式设置失败");
                    }
                    logger.trace("FTP Pasv模式设置成功");
                }
            } catch (Exception e) {
                logger.error(ftp_param.msgId, e);
                logger.error(ftp_param.msgId + " - FTP Pasv模式设置异常");
                break;
            }

            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 链接ftp失败后关闭ftp异常");
                    break;
                }
            }
            if (!StringUtil.isBlank(path)) {
                try {
                    ftp.changeWorkingDirectory(path);
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 链接ftp后更换工作目录异常");
                    break;
                }
            }

            File file2 = new File(file.getPath());
            FileInputStream input = null;
            try {
                input = new FileInputStream(file2);
                ftp.storeFile(file2.getName(), input);
            } catch (IOException e) {
                logger.error(ftp_param.msgId, e);
                logger.error(ftp_param.msgId + " - 链接ftp后上传文件异常");
                break;
            } finally {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }

                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 链接ftp操作完成后关闭ftp异常");
                    break;
                }
            }
            flag = true;
        } while (false);

        return flag;
        //可以上传目录
//		if(file.isDirectory()){
//			try {
//				ftp.makeDirectory(file.getName());
//				ftp.changeWorkingDirectory(file.getName());
//				String[] files = file.list();
//				for (int i = 0; i < files.length; i++) {
//                    File file1 = new File(file.getPath()+"\\"+files[i] );
//                    if(file1.isDirectory()){
//                        upload(file1);
//                        ftp.changeToParentDirectory();
//                    }else{
//                        File file2 = new File(file.getPath()+"\\"+files[i]);
//                        FileInputStream input = new FileInputStream(file2);
//                        ftp.storeFile(file2.getName(), input);
//                        input.close();
//                    }
//                }
//			} catch (IOException e) {
//				logger.error(ftp_param.msgId, e);
//				logger.error(ftp_param.msgId + " - 链接ftp后生成文件夹目录异常");
//			}
//		}else{
//			File file2 = new File(file.getPath());
//			FileInputStream input = null;
//			try {
//				input = new FileInputStream(file2);
//				ftp.storeFile(file2.getName(), input);
//			} catch (IOException e) {
//				logger.error(ftp_param.msgId, e);
//				logger.error(ftp_param.msgId + " - 链接ftp后文件异常");
//			} finally {
//				try {
//					input.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//		}
    }

    /**
     * 使用证书方式登录FTP服务器并上传文件
     * @param path 上传到ftp服务器哪个路径下，空时传到ftp用户根目录
     * @param file 上传的文件或文件夹
     * @param keyManager 密钥管理器，用于客户端证书认证
     * @param trustManager 信任管理器，用于验证服务器证书
     * @param logger 日志记录器
     * @return 上传是否成功
     */
    public static boolean uploadFileWithCertificate(String path, FtpParam ftp_param, File file,
                                                    KeyManager keyManager, TrustManager trustManager,
                                                    Logger logger) {
        boolean flag = false;
        //链接ftp
        FTPSClient ftp = new FTPSClient();
        int reply;

        do {
            try {
                // 设置证书
                if (keyManager != null || trustManager != null) {
                    KeyManager[] keyManagers = keyManager != null ? new KeyManager[]{keyManager} : null;
                    TrustManager[] trustManagers = trustManager != null ? new TrustManager[]{trustManager} : null;
                    ftp.setKeyManager(keyManager);
                    ftp.setTrustManager(trustManager);
                }

                ftp.connect(ftp_param.ftp_ip, ftp_param.ftp_port);
                ftp.login(ftp_param.user_name, ftp_param.password);
                ftp.execPBSZ(0);
                ftp.execPROT("P");
                ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            } catch (IOException e) {
                logger.error(ftp_param.msgId, e);
                logger.error(ftp_param.msgId + " - 链接ftp失败");
                break;
            }

            try {
                //设置PASV模式
                if (ftp_param.pasv_mode) {
                    ftp.enterLocalPassiveMode();

                    if (!(ftp.pasv() == FTPReply.ENTERING_PASSIVE_MODE)) {
                        //设置FTP PASV模式失败
                        throw new Exception("FTP Pasv模式设置失败");
                    }
                    logger.trace("FTP Pasv模式设置成功");
                }
            } catch (Exception e) {
                logger.error(ftp_param.msgId, e);
                logger.error(ftp_param.msgId + " - FTP Pasv模式设置异常");
                break;
            }

            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 链接ftp失败后关闭ftp异常");
                    break;
                }
            }
            if (!StringUtil.isBlank(path)) {
                try {
                    ftp.changeWorkingDirectory(path);
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 链接ftp后更换工作目录异常");
                    break;
                }
            }

            File file2 = new File(file.getPath());
            FileInputStream input = null;
            try {
                input = new FileInputStream(file2);
                ftp.storeFile(file2.getName(), input);
            } catch (IOException e) {
                logger.error(ftp_param.msgId, e);
                logger.error(ftp_param.msgId + " - 链接ftp后上传文件异常");
                break;
            } finally {
                try {
                    if (input != null) {
                        input.close();
                    }
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 关闭文件输入流异常");
                    break;
                }

                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    logger.error(ftp_param.msgId, e);
                    logger.error(ftp_param.msgId + " - 链接ftp操作完成后关闭ftp异常");
                    break;
                }
            }
            flag = true;
        } while (false);

        return flag;
    }

    /**
     * 使用证书方式登录FTP服务器并下载文件
     * @param ftp_param FTP连接参数
     * @param remote_file_path 远程文件路径
     * @param local_file_path 本地文件路径
     * @param rename_exist_file 是否重命名已存在的文件
     * @param keyManager 密钥管理器，用于客户端证书认证
     * @param trustManager 信任管理器，用于验证服务器证书
     * @param logger 日志记录器
     * @return 下载是否成功
     */
    public static boolean downloadFileWithCertificate(FtpParam ftp_param,
                                                      String remote_file_path,
                                                      String local_file_path,
                                                      boolean rename_exist_file,
                                                      KeyManager keyManager,
                                                      TrustManager trustManager,
                                                      Logger logger) {
        boolean dl_result = false;

        File local_file = null;
        FTPSClient ftpClient = null;
        FileOutputStream localFileStream = null;
        InetAddress address = null;

        try {
            if (null == ftp_param) {
                //参数错误
                throw new Exception("FTP配置错误,无法下载" + remote_file_path);
            }

            local_file = new File(local_file_path);
            if (local_file.exists())    //文件已存在
            {
                // 日志文件已存在
                logger.warn("FTP本地文件已存在:" + local_file_path);

                if (rename_exist_file) {
                    String rename_path = local_file_path + "." + IdMaker.Get_Random_Id(16) + ".bak";
                    File rename_file = new File(rename_path);

                    if (local_file.renameTo(rename_file))    //重命名成功
                    {
                        //重命名成功
                        logger.warn("FTP本地文件重命名成功:" + rename_path);
                    } else {
                        //重命名失败
                        throw new Exception("FTP本地文件重命名失败:" + rename_path);
                    }
                } else    //不重命名
                {
                    throw new Exception("FTP本地文件已存在,未重命名:" + local_file_path);
                }
            } else {
                String parent_path = local_file.getParent();
                File parent_dir = new File(parent_path);

                //上级目录不存在,生成
                if (!parent_dir.exists()) {
                    parent_dir.mkdirs();
                }
            }

            address = InetAddress.getByName(ftp_param.ftp_ip);

            ftpClient = new FTPSClient();

            // 设置证书
            if (keyManager != null || trustManager != null) {
                KeyManager[] keyManagers = keyManager != null ? new KeyManager[]{keyManager} : null;
                TrustManager[] trustManagers = trustManager != null ? new TrustManager[]{trustManager} : null;
                ftpClient.setKeyManager(keyManager);
                ftpClient.setTrustManager(trustManager);
            }

            ftpClient.setConnectTimeout(10 * 1000);
            ftpClient.setDefaultTimeout(10 * 1000);
            ftpClient.setDataTimeout(60 * 1000);

            ftpClient.connect(address, ftp_param.ftp_port);

            logger.trace("FTP开始连接" + ftp_param.ftp_ip + ":" + ftp_param.ftp_port);

            //登录失败
            if (!ftpClient.login(ftp_param.user_name, ftp_param.password)) {
                //日志,用户名密码错误
                throw new Exception("FTP登录失败:login_name:" + ftp_param.user_name + " login_psw:" + ftp_param.password);
            }

            // 设置安全模式
            ftpClient.execPBSZ(0);
            ftpClient.execPROT("P");

            //设置PASV模式
            if (ftp_param.pasv_mode) {
                ftpClient.enterLocalPassiveMode();

                if (!(ftpClient.pasv() == FTPReply.ENTERING_PASSIVE_MODE)) {
                    //设置FTP PASV模式失败
                    throw new Exception("FTP Pasv模式设置失败");
                }
                logger.trace("FTP Pasv模式设置成功");
            }

            localFileStream = new FileOutputStream(local_file_path);

            ftpClient.setBufferSize(1024);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.retrieveFile(remote_file_path, localFileStream);

            //FTP下载失败
            if ((ftpClient.getReplyCode() != FTPReply.CLOSING_DATA_CONNECTION)) {
                //日志
                throw new Exception("FTP下载失败,FtpReplayCode:" + ftpClient.getReplyCode());
            }

            logger.debug("FTP下载文件成功,保存于:" + local_file_path);

            //到此下载成功
            dl_result = true;
        } catch (Exception e) {
            //日志 下载文件异常
            logger.error("FTP下载异常:" + e);
        } finally {
            try {
                if (localFileStream != null) {
                    localFileStream.flush();
                    localFileStream.close();
                }

                if (null != ftpClient) {
                    ftpClient.disconnect();
                }

                if (!dl_result)    //下载失败
                {
                    local_file = new File(local_file_path);
                    if (local_file.exists()) {
                        local_file.delete();
                        logger.trace("FTP 下载失败,清理临时文件成功");
                    }
                }
            } catch (Exception e) {
                //出现异常
                logger.error("FTP下载失败,finally异常:" + e);
            }
        }
        return dl_result;
    }

    //Test
    public static void main(String[] args) {

        FtpParam ftp_param = new FtpParam();

        ftp_param.ftp_ip = "123.232.43.26";
        ftp_param.ftp_port = 12521;
        ftp_param.user_name = "ftptest";
        ftp_param.password = "xingyu803";
        ftp_param.pasv_mode = true;

        String local_file_path = "D://abcde123";

        uploadFile("", ftp_param, new File(local_file_path), LoggerFactory.getLogger("System"));


//		FtpParam ftp_param = new FtpParam();
//
//		ftp_param.ftp_ip = "192.168.1.33";
//		ftp_param.ftp_port = 21;
//		ftp_param.user_name = "applog";
//		ftp_param.password = "applog12345";
//		ftp_param.pasv_mode = true;
//
//		String remote_file_path = "/LtyService/logs/System.log";
//		String local_file_path = "D:/dl.log";
//
//		DownLoadFtpFile(ftp_param, remote_file_path, local_file_path, true, LoggerFactory.getLogger("System"));
    }

    //FTP参数
    public static class FtpParam {
        public String msgId = "";
        public String ftp_ip = "";    //FTP地址
        public int ftp_port = 21;                //FTP端口
        public String user_name = "";        //FTP用户名
        public String password = "";        //FTP密码
        public boolean pasv_mode = false;    //被动模式
    }
}

